直接附上我的 code
extern _main
extern _printf
extern _scanf
section .data
sca_fm: db "%d",0
pri_fm: db "%d",10,0
seed: dd 1
count: dd 1
section .bss
random: resd 1
time: resd 1
section .text
_main:
push ebp
mov ebp, esp
push time
push sca_fm
call _scanf
add ebp, 8
rand: mov eax, [seed]
imul eax, eax, 0x343fd
add eax, 0x269ec3
mov [seed], eax
mov [random], eax
sar eax, 0x10
and eax, 0x7fff
mov [random],eax
push eax
push pri_fm
call _printf
add ebp, 8
mov eax, [count]
add eax, 1
mov [count], eax
mov ecx, [time]
cmp ecx, eax
jnl rand
pop ebp
retn
基本上就是類似於昨天給的那串 C,接下來就簡單介紹一下我寫的 code。
extern _main
extern _printf
extern _scanf
這段是引入外部函數,要注意 main 前面一定要加底線,否則 linker 會找不到你的 main 函數,但經過我測試後,也可以宣告為 global,但我目前還不太清楚兩者在實際上會產生怎樣的差異,因為測試下是都可以正常執行完成的。
section .data
sca_fm: db "%d",0
pri_fm: db "%d",10,0
seed: dd 1
count: dd 1
這段是宣告初始化變數,sca_fm 是給 scanf 的格式化字串,pri_fm 是給 printf 的格式化字串,seed 是初始種子碼,count 是計數器,計算目前已經計算到第幾個亂數。
section .bss
random: resd 1
time: resd 1
這段是宣告為初始化變數,random 是存放產生出的亂數,time 是我們要求的次數。
_main:
push ebp
mov ebp, esp
.
.
.
pop ebp
ret
這部分是 Day4 所提到的平棧。
push time
push sca_fm
call _scanf
add ebp, 8
這裡是把 scanf 的參數傳進 Stack 中並呼叫 scanf,再因為 stdcall 的呼叫慣例來進行 Stack 的調整。
rand: mov eax, [seed]
imul eax, eax, 0x343fd
add eax, 0x269ec3
mov [seed], eax
sar eax, 0x10
and eax, 0x7fff
mov [random],eax
push eax
push pri_fm
call _printf
add ebp, 8
mov eax, [count]
add eax, 1
mov [count], eax
mov ecx, [time]
cmp ecx, eax
jnl rand
這段是亂數產生器的實現過程,rand 是我的標籤,前三分段是亂數產生器的演算法,第四段是 printf 函數,第五段是將計數器加一並存回去,最後一段是將計數器與要求次數相比較,之後用帶有判斷的跳轉指令跳回到 rand 標籤處,至此已經完成了我們的亂數產生器。又或是可以變化成輸入種子碼,再進行亂數產生,以達到更貼近正常使用上的亂數產生。
基本上我的主題已經談得差不多了,我所碰過的問題與解與相關知識也大致上都提出來講過一次了,所以之後的內容我應該會將前面的主題再提出一些更細的細節來說,雖然大概率可能會跟組語沒有直接關係,或是如果我有想到一些實作的主題,又或者有人有想做的目標可以提出來一起挑戰。